type TreeNode = { [key: string]: any };
type FieldNames = { label?: string; value?: string; children?: string };
type CheckedKeyObj = { checked: React.Key[]; halfChecked: React.Key[] };

/**
 * 获取最终列名映射结果
 * @param fieldNames 列名映射
 * @returns 最终映射结果
 */
function getEndFieldNames(
  fieldNames: FieldNames = {
    label: 'label',
    value: 'value',
    children: 'children',
  },
) {
  const endFieldNames = {
    label: fieldNames?.label || 'label',
    value: fieldNames?.value || 'value',
    children: fieldNames?.children || 'children',
  };
  return endFieldNames;
}

/**
 * 获取所有 key
 * @param treeData 数据
 * @param fieldNames 名称
 * @param res 初始值
 * @returns 结果
 */
export function getAllKeysTree(
  treeData: TreeNode[],
  fieldNames: { key?: string; children?: string } = {
    key: 'key',
    children: 'children',
  },
  res: React.Key[] = [],
): React.Key[] {
  const endFieldNames = {
    key: fieldNames?.key || 'key',
    children: fieldNames?.children || 'children',
  };
  treeData.forEach((item) => {
    const key = item[endFieldNames.key];
    if (key !== undefined) {
      res.push(key);
    }
    const children = item[endFieldNames.children];
    if (Array.isArray(children) && children.length > 0) {
      getAllKeysTree(children, fieldNames, res);
    }
  });
  return res;
}

/**
 * 查询节点
 * @param treeData 数据
 * @param key 查询的 key
 * @param fieldNames 列名映射
 * @returns 查询结果
 */
export function findItemInTree(
  treeData: TreeNode[],
  key: React.Key,
  fieldNames: FieldNames = {
    label: 'label',
    value: 'value',
    children: 'children',
  },
): TreeNode | null {
  const endFieldNames = getEndFieldNames(fieldNames);
  for (let i = 0, limit = treeData.length; i < limit; i++) {
    const item = treeData[i];
    if (key === item[endFieldNames.value]) {
      return item;
    }
    const children = item[endFieldNames.children];
    if (Array.isArray(children) && children.length > 0) {
      const res = findItemInTree(children, key, endFieldNames);
      if (res) {
        return res;
      }
    }
  }
  return null;
}

/**
 * 判断当前节点是否全选中
 * @param treeData 树状数据
 * @param key 查询id
 * @param keys 已经选中列表
 * @param fieldNames 映射名称
 * @returns 是否全选中
 */
export function keyIsCheckedAllChildren(
  treeData: TreeNode[],
  key: React.Key,
  keys: React.Key[],
  fieldNames: FieldNames = {
    label: 'label',
    value: 'value',
    children: 'children',
  },
): boolean {
  const keySet = new Set(keys);
  if (!keySet.has(key)) {
    return false;
  }
  const endFieldNames = getEndFieldNames(fieldNames);
  const item = findItemInTree(treeData, key, endFieldNames);

  if (!item) {
    return false;
  }

  const children = item[endFieldNames.children];

  if (Array.isArray(children) && children.length > 0) {
    const allKey = getAllKeysTree(children, {
      key: endFieldNames.value,
      children: endFieldNames.children,
    });
    for (let i = 0, limit = allKey.length; i < limit; i++) {
      if (!keySet.has(allKey[i])) {
        return false;
      }
    }
  }
  return true;
}

/**
 * 选中状态分组
 * @param treeData 数据
 * @param keys 当前的 key
 * @param fieldNames 列名映射
 * @returns 分类结果
 */
export function groupCheckedKey(
  treeData: TreeNode[],
  keys: React.Key[],
  fieldNames: FieldNames = {
    label: 'label',
    value: 'value',
    children: 'children',
  },
): CheckedKeyObj {
  const res: CheckedKeyObj = {
    checked: [],
    halfChecked: [],
  };
  keys.forEach((key) => {
    if (keyIsCheckedAllChildren(treeData, key, keys, fieldNames)) {
      res.checked.push(key);
    } else {
      res.halfChecked.push(key);
    }
  });

  return res;
}

/**
 * 查询父级 id
 * @param treeData 数据
 * @param key 查询 key
 * @param fieldNames 列名映射
 * @param initRootParentId 初始化父级 id
 * @returns 查询结果
 */
function findParentId(
  treeData: TreeNode[],
  key: React.Key,
  fieldNames: FieldNames = {
    label: 'label',
    value: 'value',
    children: 'children',
  },
  initRootParentId: React.Key | null = null,
): React.Key | null {
  const endFieldNames = {
    label: fieldNames?.label || 'label',
    value: fieldNames?.value || 'value',
    children: fieldNames?.children || 'children',
  };
  for (let i = 0, limit = treeData.length; i < limit; i++) {
    const item = treeData[i];
    const id = item[endFieldNames.value];
    if (id === key) {
      return initRootParentId;
    }
    const children = item[endFieldNames.children];
    if (Array.isArray(children) && children.length > 0) {
      const parentId = findParentId(children, key, fieldNames, id);
      if (parentId !== null) {
        return parentId;
      }
    }
  }
  return null;
}

/**
 * 根据 key 列表查询所有父级 id
 * @param treeData 数据
 * @param keys 查询 key 列表
 * @param fieldNames 列名映射
 * @returns 查询结果
 */
export function findParentIdListByIdList(
  treeData: TreeNode[],
  keys: React.Key[],
  fieldNames: FieldNames = {
    label: 'label',
    value: 'value',
    children: 'children',
  },
): React.Key[] {
  const res: Set<React.Key> = new Set();
  keys.forEach((key) => {
    const parentId = findParentId(treeData, key, fieldNames);
    if (parentId !== '' && parentId !== null && parentId !== undefined) {
      res.add(parentId);
    }
  });
  return Array.from(res);
}

/**
 * 查询父节点链表
 * @param treeData 数据
 * @param key 查询 key
 * @param fieldNames 列名映射
 * @param initParentList 初始化父级列表
 * @returns 查询结果
 */
export function findParentListById(
  treeData: TreeNode[],
  key: React.Key,
  fieldNames: FieldNames = {
    label: 'label',
    value: 'value',
    children: 'children',
  },
  initParentList: TreeNode[] = [],
): { res: boolean; parentList: TreeNode[] } {
  const endFieldNames = getEndFieldNames(fieldNames);
  for (let i = 0, limit = treeData.length; i < limit; i++) {
    const item = treeData[i];
    const id = item[endFieldNames.value];
    if (id === key) {
      return { res: true, parentList: initParentList };
    }
    const children = item[endFieldNames.children];
    if (Array.isArray(children) && children.length > 0) {
      const res = findParentListById(children, key, endFieldNames, [...initParentList, item]);
      if (res.res) {
        return res;
      }
    }
  }
  return {
    res: false,
    parentList: initParentList,
  };
}

/**
 * 查询所有父节点 id 链表
 * @param treeData 数据
 * @param key 查询 key
 * @param fieldNames 列名映射
 * @returns 父级列表
 */
export function findParentIdListById(
  treeData: TreeNode[],
  key: React.Key,
  fieldNames: FieldNames = {
    label: 'label',
    value: 'value',
    children: 'children',
  },
): React.Key[] {
  const endFieldNames = getEndFieldNames(fieldNames);
  return findParentListById(treeData, key, endFieldNames).parentList.map((item) => {
    return item[endFieldNames.value];
  });
}
